package com.cg.bank.service;

import java.io.IOException;
import java.util.List;

import com.cg.bank.dao.BankDao;
import com.cg.bank.domain.Transaction;
import com.cg.bank.domain.User;
import com.cg.bank.factory.BankDaoFactory;
import com.cg.bank.util.DepositException;
import com.cg.bank.util.JdbcUtils;
import com.cg.bank.util.MD5;
import com.cg.bank.util.Page;
import com.cg.bank.util.TransferException;
import com.cg.bank.util.UserException;
import com.cg.bank.util.WithdrawalException;
import com.cg.bank.web.util.AppException;

/**
 * @author chunges
 * @version V1.0
 * @Description ManagerImpl业务(单例加同步)
 * @date 2018年6月12日 上午7:37:31
 */

public class ManagerImpl implements ManagerInterface {
	/**
	 * 单笔转账最大金额限制
	 */
    private static final double LIMITTRANSFERMONEY = 20000;
    /**
     * 单笔存款最大金额限制
     */
    private static final double LIMITDEPOSTIMONEY = 50000;
    /**
     * 单笔取款最大金额限制
     */
    private static final double LIMITWITHDRAWALMONEY = 10000;
    
	private static volatile ManagerImpl instance;
    private BankDao bankDao;

    // 通过工厂装载DaoImpl对象
    private ManagerImpl() throws IOException, ReflectiveOperationException {
        bankDao = BankDaoFactory.getInstance().getBankDaoInstance();
    }

    /**
     * 获得ManagerImpl实例
     *
     * @return ManagerImpl instance
     */
    public static ManagerImpl getInstance() throws IOException, ReflectiveOperationException {
        if (ManagerImpl.instance == null) {
            synchronized (ManagerImpl.class) {
                if (ManagerImpl.instance == null) {
                    ManagerImpl.instance = new ManagerImpl();
                }
            }
        }

        return instance;
    }

    /**
     * 余额查询
     *
     * @return result money 返回余额
     */
    @Override
    public double queryBalance(User user) {
        return bankDao.getBalanceByAccount(user.getId());
    }
    
    @Override
    public User queryUserByAccount(String account) {
        return bankDao.getUserByAccount(account);
    }

    /**
     * 查询指定用户交易记录
     *
     * @param user 需要查询的用户
     * @param page 分页器 
     * @return
     */
    @Override
    public List<Transaction> queryTransactionRecordByAccount(User user, Page page) {
    	if (page.getRecordCount() <= 0) {
    		page.setRecordCount( bankDao.getTransactionCountsByAccount(user.getId()));
    	}
    	return bankDao.getTransactionRecordByAccount(user.getId(), page);
    }
    
    /**
     * 查询指定用户交易记录
     *
     * @param page 分页器 
     * @return
     */
    @Override
	public List<Transaction> queryAllTransactionRecord(Page page) {
    	if (page.getRecordCount() <= 0) {
    		page.setRecordCount(bankDao.getTransactionCounts());
    	}
		return bankDao.getAllTransactionRecord(page);
	}

    /**
     * 存款业务
     *
     * @param user  存款账户
     * @param money 需要存入的金额
     * @return deposit result 返回存款结果
     * @throws DepositException 存款负数异常
     */
    @Override
    public void deposit(User user, double money) {
        if (money < 0) {
        	// 存款金额不能为负
        	throw new AppException("transaction.error.depositInput");
        } else if (money >= LIMITDEPOSTIMONEY) {
        	// 单笔存款金额超出限额
        	throw new AppException("transaction.error.deposit", new Object[]{LIMITDEPOSTIMONEY});
        }
        bankDao.updateBalance(user.getId(), money);
    }

    /**
     * 添加交易信息
     *
     * @param transaction
     */
    @Override
    public void addTransactionRecord(Transaction transaction) {
        bankDao.addTransactionRecord(transaction);
    }

    /**
     * 取款业务
     *
     * @param user  取款账户
     * @param money 取款金额
     * @return withdrawal.jsp result 取款结果
     * @throws WithdrawalException 取款超出异常
     */
    @Override
    public void withdrawal(User user, double money) {
        // 取款金额不能为负
        if (money <= 0) {
        	throw new AppException("transaction.error.withdrawalInput");
        } else if (money > LIMITWITHDRAWALMONEY) {
        	// 单笔取款金额超出限额
        	throw new AppException("transaction.error.overMaxWithdrawal",new Object[]{LIMITWITHDRAWALMONEY});
        }
        
        double balance;
        // 查询余额并更新
        if (money <= (balance = queryBalance(user))) {
            // 余额更新默认是加操作(内部运算时变成-)
            bankDao.updateBalance(user.getId(), -money);
        } else {
            // 余额不足
        	throw new AppException("transaction.error.withdrawal", new Object[]{balance});
        }
    }

    /**
     * 转账业务
     *
     * @param fromUser      转账发起用户
     * @param toUser        转账接收用户
     * @param transferMoney 转账金额
     * @return transfer result 转账结果
     * @throws TransferException 非法转账金额异常
     * @throws UserException     用户未注册异常
     */
    @Override
    public void transfer(User fromUser, User toUser, double transferMoney){
        // 转账发起者余额合法性(该数据从缓存中查询)[存在更新问题]
    	// 检查转账用户存在合法性
    	if (toUser == null) {
    		throw new AppException("transaction.error.noTransferUser");
    	}
    	// 转账金额非法
    	if (transferMoney <= 0) {
    		throw new AppException("transaction.error.transferInput");
    	}
    	// 余额不足
        if (transferMoney > fromUser.getBalance()) {
        	throw new AppException("transaction.error.overTransferBalance", new Object[] {fromUser.getBalance()});
        }
        // 检查收款人是否为自己
        if (fromUser.getId() == toUser.getId()) {
        	throw new AppException("transaction.error.selfTransfer");
        }
        // 单笔转账限额
        if (transferMoney > LIMITTRANSFERMONEY) {
        	throw new AppException("transaction.error.overMaxTransfer", new Object[] {LIMITTRANSFERMONEY});
        }
        try {
            // 开启事务
            JdbcUtils.beginTransaction();
            bankDao.updateBalance(fromUser.getId(), -transferMoney);
            bankDao.updateBalance(toUser.getId(), transferMoney);
            // 提交事务
            JdbcUtils.commitTransaction();
        } catch (Exception e) {
            e.printStackTrace();
            try {
                // 回滚事务
                JdbcUtils.rollbackTransaction();
            } catch (Exception e1) {
            	// 转账失败
            	throw new AppException("transaction.error.transfer");
            }
        }
    }

    /**
     * 用户注册
     *
     * @param userForm 需注册用户
     * @return register result 注册结果
     */
    @Override
    public void register(User userForm) {
        User user = bankDao.getUserByAccount(userForm.getAccount());
        // 能查询到用户信息表明用户已存在
        if (user != null) {
        	throw new AppException("user.error.register");
        }
        bankDao.addUser(userForm);// 添加用户信息
    }

    /**
     * 用户登录
     *
     * @param formUser
     * @return login result 登录结果
     * @throws UserException 未注册异常
     */
    @Override
    public User login(User formUser) {
        User user = bankDao.getUserByAccount(formUser.getAccount());
        // 用户不存在
        if (user == null) {
            throw new AppException("user.error.loginForward");
        }
        String formPass = MD5.getMD5(formUser.getPassword());
        // 表单中的用户登录信息与数据库中的校验
        if (formUser.getAccount().equals(user.getAccount()) && formPass.equals(user.getPassword())) {
            return user;
        } else {
        	// 密码错误
        	throw new AppException("user.error.loginForward");
        }
    }

    /**
     * 更新账户信息
     *
     * @param user 需要更新用户的信息
     */
    @Override
    public void updateUserInformation(User user) {
        bankDao.updateUserInformation(user);
    }

    /**
     * 用户注销(登出)
     */
    @Override
    public void logout(User accountID) {
        //
    }

    /**
     * 注销用户信息
     *
     * @param user 需要注销的用户
     */
    @Override
    public void logoffAccount(User user) {
        // 确认验证控制[暂存用户记录]
        bankDao.deleteUserByAccount(user.getId());
    }
    
}